package com.zenghus.spring.formework.webmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;

/**
 * @author zenghu
 * @date 2018/5/1 16:11
 */
public class HandlerAdapter {
    private Map<String,Integer> paramMapping;

    public HandlerAdapter(Map<String,Integer> param){
        this.paramMapping=param;
    }

    /**
     *
     * @param req
     * @param resp
     * @param handlerMapping    包含controller,method,url
     * @return
     */
    public ModelAndView handler(HttpServletRequest req, HttpServletResponse resp, HandlerMapping handlerMapping) {
        //根据用户请求的参数信息，没跟method中的参数信息尽心动态匹配

        //resp传进来的目的只有一个，只是为了将其赋值给方法参数仅此而已
        //只有当用户传过来的ModelAndView为空的时候，才会初始化一个新的

        //1.得到当方法的形参列表
        Class<?>[] paramTypes=handlerMapping.getMethod().getParameterTypes();
        //2.拿到自定义命名参数所在的位置
        //用户通过url传过来的参数列表
        Map<String,String[]> map=req.getParameterMap();

        //3.构造实参列表
        Object[] paramValues=new Object[paramTypes.length];
        for (Map.Entry<String,String[]> p:map.entrySet()) {
            String value= Arrays.toString(p.getValue()).replaceAll("\\[|\\]","").replaceAll("\\s","");
            if(!this.paramMapping.containsKey(p.getKey())){continue; }

            int index=this.paramMapping.get(p.getKey());

            //页面传过来的值都是String类型，而方法的值是不确定的
            //要针对方法的参数进行类转换
            paramValues[index]=caseStringValue(value,paramTypes[index]);

        }
        if(this.paramMapping.containsKey(HttpServletRequest.class.getName())){
            int reqIndex=this.paramMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex]=req;
        }

        if(this.paramMapping.containsKey(HttpServletResponse.class.getName())) {
            int respIndex = this.paramMapping.get(HttpServletResponse.class.getName());
            paramValues[respIndex] = resp;
        }


        //4.从handler中取出controller，method然后通过反射机制进行调用
        try {
            Object result=handlerMapping.getMethod().invoke(handlerMapping.getController(),paramValues);
            if(result==null){return null;}
            if(handlerMapping.getMethod().getReturnType()==ModelAndView.class){
                return (ModelAndView)result;
            }else{
                return null;
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }

    private Object caseStringValue(String value,Class<?> clazz){
        if(clazz==String.class){
            return value;
        }else if(clazz==Integer.class){
            return Integer.valueOf(value);
        }else if (clazz==int.class){
            return Integer.valueOf(value).intValue();
        }else{
            return null;
        }
    }
}
